import GeoJSON from 'ol/format/GeoJSON'
import VectorLayer from 'ol/layer/Vector'
import Point from 'ol/geom/Point'
import { Vector as VectorSource } from 'ol/source'
import { useInjectMap } from './hooks/use-inject-map'
import parseStyle from './utils/style'
import Feature from 'ol/Feature'
import { StyleLike } from 'ol/style/Style'
import { click, pointerMove } from 'ol/events/condition.js'
import Select from 'ol/interaction/Select'

const defaultStyleCreator = (config) => {
  return (feature) => {
    const size = (feature.get('features') || []).length
    const { fill, radius, strokeWidth, strokeColor, textFill, scaleSeed } = config
    return parseStyle({
      circle: {
        radius: radius + scaleSeed * size,
        stroke: {
          width: strokeWidth,
          color: strokeColor
        },
        fill: fill
      },
      text: {
        text: size > 0 ? size.toString() : '',
        fill: textFill
      }
    })
  }
}

export default defineComponent({
  name: 'MapMarker',
  props: {
    data: Array,
    zIndex: Number,
    layerStyle: {
      type: [Function, Object],
      default() {
        return {
          fill: '#409eff',
          radius: 10,
          strokeWidth: 1,
          strokeColor: '#fff',
          textFill: '#fff',
          scaleSeed: 0.001
        }
      }
    },
    trigger: {
      type: String,
      default: 'click',
      validator(val: string) {
        return ['click', 'hover'].includes(val)
      }
    }
  },
  emits: ['show', 'hide'],
  setup(props, { emit }) {
    const { map } = useInjectMap()
    const geoLayer = shallowRef()

    const setStyle = (feature) => {
      const { style } = feature.get('data')
      const styleFun = style ? parseStyle(style) : defaultStyleCreator(props.layerStyle)
      return styleFun
    }

    const addLayer = () => {
      const style = typeof props.layerStyle === 'function' ? props.layerStyle : setStyle

      const source = new VectorSource({
        format: new GeoJSON()
      })

      geoLayer.value = new VectorLayer({
        source,
        style: style as StyleLike,
        zIndex: props.zIndex
      })
      map?.addLayer(geoLayer.value)
      nextTick(() => {
        bindEvents()
        props.data && draw(props.data)
      })
    }

    const draw = (json: any[]) => {
      const features = json.map(
        (item: any) =>
          new Feature({
            geometry: new Point(item['coordinate']),
            data: item
          })
      )

      const source = geoLayer.value.getSource()
      source?.addFeatures(features)
    }

    const clear = () => {
      const source = geoLayer.value?.getSource()
      source?.clear()
    }

    addLayer()

    watch(
      () => props.data,
      (newwale) => {
        clear()
        newwale && draw(newwale)
      },
      { immediate: true }
    )

    const bindEvents = () => {
      const condition =
        props.trigger === 'click' ? click : props.trigger === 'click' ? pointerMove : undefined
      if (!condition) return false

      const marksEvents = new Select({
        condition: condition,
        hitTolerance: 5 // 命中容差默认是5
      })
      map?.addInteraction(marksEvents)
      marksEvents.on('select', (e) => {
        const selectedfeature = e.selected
        showPopup(e, selectedfeature)
      })
    }

    const showPopup = (e, features) => {
      // if (!features) return
      // const coordinate = feature.getGeometry().getCoordinates()
      // const features = feature.get('features') || []
      // const marker = {
      //   coordinate,
      //   cluster: false,
      //   items: [] as any
      // }
      // if (features.length > 0) {
      //   marker.items = features.map((f) => f.get('data'))
      //   marker.cluster = true
      // } else {
      //   marker.items = [feature.get('data')]
      // }
      if (features.length > 0) {
        const coordinate = features[0].getGeometry().getCoordinates()
        const marker = {
          coordinate,
          cluster: false,
          items: [] as any
        }
        emit('show', marker, features[0], e)
      }
    }

    const handleHide = () => {
      emit('hide')
    }

    onBeforeUnmount(() => {
      clear()
      map?.removeLayer(geoLayer.value)
    })

    return {}
  },
  render() {
    return null
  }
})
